package com.example.newinfinity.View.DrawShape

import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
import android.graphics.Region
import com.example.newinfinity.IconModel.IconState
import com.example.newinfinity.MyViewModel.DrawViewModel
import com.example.newinfinity.R

/*所有绘制的图形继承该抽象类 重写其中的抽象方法*/
abstract class Shape {
    var startX: Float = 0f
    var startY: Float = 0f
    var endX: Float = 0f
    var endY: Float = 0f
    var centerX: Float = 0f
    var centerY: Float = 0f
    var rectF = RectF()  //起始位置与终点位置确定的矩形区域
    var mPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { //绘制用的画笔
        this.color = DrawViewModel.getDrawViewModel().mColor
        this.strokeWidth = DrawViewModel.getDrawViewModel().mStrokeWidth
        this.style = DrawViewModel.getDrawViewModel().mStyle
    }

    //保存拖拉点拽操作中 每个图形的选中状态 是否显示选中边框
    var shapeSelectedState = IconState.NORMAL   //默认不选中

    //绘制选中边框的画笔
    private val borderPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        this.color = Color.parseColor("#6375FE")
        this.strokeWidth = 6f
        this.style = Paint.Style.STROKE
    }

    //显示边框上的四个小圆（Bitmap）
    private val circleBitmap = BitmapFactory.decodeResource(
        DrawViewModel.getDrawViewModel().getContext().resources,
        R.drawable.scale_corner
    )

    //四个小圆的半径
    private val circleRadius = 12f

    //拖拉点拽二次点击时 保存二次点击操作的类型
    private var moveType = MoveType.NONE

    //图形绘制的路径
    var mPath = Path()

    //起始位置确定
    open fun setStartPoint(x: Float, y: Float) {
        startX = x
        startY = y
    }

    //终点位置确认
    open fun setEndPoint(x: Float, y: Float) {
        endX = x
        endY = y
        //计算中心位置
        centerX = (startX + endX) / 2
        centerY = (startY + endY) / 2
        rectF.apply {
            this.left = Math.min(startX, endX)
            this.right = Math.max(startX, endX)
            this.top = Math.min(startY, endY)
            this.bottom = Math.max(startY, endY)
        }
    }

    //专门提供给橡皮擦显示矩形的显示状态清空方法 DrawView中手up矩形显示及消失
    open fun changeEraserRectShowState() {}

    //具体绘制图形的方法
    open fun draw(canvas: Canvas) {
        //如果拖拉点拽时 图形已选中 则显示包裹边框及四个拖拉圆点
        if (shapeSelectedState == IconState.SELECTED) {
            canvas.drawRect(rectF, borderPaint)  //边框
            canvas.drawBitmap(
                circleBitmap,
                rectF.left - circleRadius,
                rectF.top - circleRadius,
                null
            )  //左上角的圆
            canvas.drawBitmap(
                circleBitmap,
                rectF.right - circleRadius,
                rectF.top - circleRadius,
                null
            )  //右上角的圆
            canvas.drawBitmap(
                circleBitmap,
                rectF.left - circleRadius,
                rectF.bottom - circleRadius,
                null
            )  //左下角的圆
            canvas.drawBitmap(
                circleBitmap,
                rectF.right - circleRadius,
                rectF.bottom - circleRadius,
                null
            )  //右下角的圆
        }
    }

    //判断触摸点是否在当前图形真正显示内部
    open fun containsPointInPath(x: Float, y: Float): Boolean {
        val region = Region()
        val clipRegion = Region(
            rectF.left.toInt(),
            rectF.top.toInt(),
            rectF.right.toInt(),
            rectF.bottom.toInt()
        )
        region.setPath(mPath, clipRegion)    //在clipRegion区域内裁切mPath中的图案
        return region.contains(x.toInt(), y.toInt())
    }

    //触摸点在图形内部就填充颜色
    open fun fillColor() {
        mPaint.color = DrawViewModel.getDrawViewModel().mColor
    }

    //拖拉点拽操作中 点击修改图形的选中状态 是否显示选中边框的方法
    open fun changeIconSelectedState() {
        shapeSelectedState = if (shapeSelectedState == IconState.NORMAL) {
            IconState.SELECTED
        } else {
            IconState.NORMAL
        }
    }

    //判断是否选中图形时需要稍微扩大一点矩形的区域 防止拖拉点拽时判断为点击到了图形外部
    private var newRectF = RectF()
    private val addSize = 20f //向外围稍微扩大一点的尺寸

    //判断触摸点是否在当前图形的rectF内部
    open fun containsPointInRectF(x: Float, y: Float): Boolean {
        newRectF = RectF().apply {
            this.left = rectF.left - addSize
            this.top = rectF.top - addSize
            this.right = rectF.right + addSize
            this.bottom = rectF.bottom + addSize
        }
        return newRectF.contains(x, y)
    }

    //二次点击拖拉点拽操作时 计算二次点击的位置 判断操作的类型
    open fun calculateMoveType(x: Float, y: Float) {
        //判断触摸点位置
        if (x in newRectF.left..newRectF.left + 2 * addSize && y in newRectF.top..newRectF.top + 2 * addSize) {
            moveType = MoveType.LEFT_TOP
        } else if (x in newRectF.right - 2 * addSize..newRectF.right && y in newRectF.top..newRectF.top + 2 * addSize) {
            moveType = MoveType.RIGHT_TOP
        } else if (x in newRectF.left..newRectF.left + 2 * addSize && y in newRectF.bottom - 2 * addSize..newRectF.bottom) {
            moveType = MoveType.LEFT_BOTTOM
        } else if (x in newRectF.right - 2 * addSize..newRectF.right && y in newRectF.bottom - 2 * addSize..newRectF.bottom) {
            moveType = MoveType.RIGHT_BOTTOM
        } else if (x in newRectF.left..newRectF.left + 2 * addSize && y in newRectF.top + 2 * addSize..newRectF.bottom - 2 * addSize) {
            moveType = MoveType.LEFT
        } else if (x in newRectF.left + 2 * addSize..newRectF.right - 2 * addSize && y in newRectF.top..newRectF.top + 2 * addSize) {
            moveType = MoveType.TOP
        } else if (x in newRectF.right - 2 * addSize..newRectF.right && y in newRectF.top + 2 * addSize..newRectF.bottom - 2 * addSize) {
            moveType = MoveType.RIGHT
        } else if (x in newRectF.left + 2 * addSize..newRectF.right - 2 * addSize && y in newRectF.bottom - 2 * addSize..newRectF.bottom) {
            moveType = MoveType.BOTTOM
        } else {
            moveType = MoveType.CENTER
        }
        startMoveOperation(moveType, x, y)  //进行点击到对应区域对应的操作
    }

    //根据二次点击的位置判断接下来拖拉点拽的操作
    private fun startMoveOperation(type: MoveType, x: Float, y: Float) {
        when (type) {
            MoveType.NONE -> {}
            else -> {
                //记录点击起始移动点
                moveStartX = x
                moveStartY = y
            }
        }
    }

    //用于接收移动操作中的 点击起始移动点
    private var moveStartX = 0f
    private var moveStartY = 0f
    //接收移动操作中 真正需要获取并改变图形rectF的移动距离
    var xMoveSpace = 0f
    var yMoveSpace = 0f

    //二次点击图形并开始移动时会传入移动位置的实时坐标
    //calculateMoveType方法中 当用户二次点击时 已判断好了操作的类型
    fun getMoveDistance(xDistance: Float, yDistance: Float) {
        if (moveType == MoveType.CENTER) {  //二次点击在中心区域才是进行移动操作
            //获取移动时起始点和移动点坐标的差值 即移动距离
            xMoveSpace = xDistance - moveStartX
            yMoveSpace = yDistance - moveStartY

            //开始改变图形的startX startY endX endY
            startX += xMoveSpace
            endX += xMoveSpace
            startY += yMoveSpace
            endY += yMoveSpace

            //更新移动的起始点为上次移动终点的位置 防止累加
            moveStartX = xDistance
            moveStartY = yDistance

            //更新rectF区域
            rectF.offset(xMoveSpace, yMoveSpace)

            //更新outSideRectF 点击是否选中的区域（矩形适用）
            newRectF.offset(xMoveSpace, yMoveSpace)

            //某些图形是否选中的判断是根据裁切过后的具体图形路径mPath所以也需要更新mPath（三角形 圆形 贝塞尔曲线等）
            mPath.offset(xMoveSpace, yMoveSpace)
        }
        if (moveType == MoveType.LEFT) {
            changeLeftLength(xDistance)
        }
        if (moveType == MoveType.RIGHT) {
            changeRightLength(xDistance)
        }
        if (moveType == MoveType.TOP) {
            changeTopLength(yDistance)
        }
        if (moveType == MoveType.BOTTOM) {
            changeBottomLength(yDistance)
        }
        if (moveType == MoveType.LEFT_TOP) {
            changeLeftLength(xDistance)
            changeTopLength(yDistance)
        }
        if (moveType == MoveType.RIGHT_TOP) {
            changeRightLength(xDistance)
            changeTopLength(yDistance)
        }
        if (moveType == MoveType.LEFT_BOTTOM) {
            changeLeftLength(xDistance)
            changeBottomLength(yDistance)
        }
        if (moveType == MoveType.RIGHT_BOTTOM) {
            changeRightLength(xDistance)
            changeBottomLength(yDistance)
        }
    }

    //移动操作中 改变图形左边长度的方法
    private fun changeLeftLength(xDistance: Float) {
        xMoveSpace = xDistance - moveStartX  //获取左侧拉动距离
        //判断图形是如何拉动形成的（从左往右 从右往左）
        if (startX < endX) { //从左往右
            startX += xMoveSpace //修改起始点的X坐标
        } else { //从右往左
            endX += xMoveSpace //修改移动终点的X坐标
        }
        //重新初始化起始点为上次移动的终点 防止累加
        moveStartX = xDistance

        //修改rectF的left
        rectF.left += xMoveSpace

        //更新outSideRectF 点击是否选中的区域（矩形适用）
        newRectF.left += xMoveSpace

        //某些图形是否选中是根据裁切过后的具体图形路径mPath 所以也需要更新mPath（三角形 圆形 贝塞尔曲线等）
        //mPath.offset(xMoveSpace, yMoveSpace)
    }

    //移动操作中 改变图形右边长度的方法
    private fun changeRightLength(xDistance: Float) {
        xMoveSpace = xDistance - moveStartX  //获取右侧拉动距离
        //判断图形是如何拉动形成的（从左往右 从右往左）
        if (startX < endX) { //从左往右
            endX += xMoveSpace //修改起始点的X坐标
        } else { //从右往左
            startX += xMoveSpace //修改移动终点的X坐标
        }
        //重新初始化起始点为上次移动的终点 防止累加
        moveStartX = xDistance
        //修改rectF的left
        rectF.right += xMoveSpace

        //更新outSideRectF 点击是否选中的区域（矩形适用）
        newRectF.right += xMoveSpace

        //某些图形是否选中是根据裁切过后的具体图形路径mPath 所以也需要更新mPath（三角形 圆形 贝塞尔曲线等）
        //mPath.offset(xMoveSpace, yMoveSpace)
    }

    //移动操作中 改变图形上方长度的方法
    private fun changeTopLength(yDistance: Float) {
        yMoveSpace = yDistance - moveStartY  //获取上方拉动距离
        //判断图形是如何拉动形成的（从上往下 从下往上）
        if (startY < endY) { //从上往下
            startY += yMoveSpace //修改起始点的Y坐标
        } else { //从下往上
            endY += yMoveSpace //修改移动终点的Y坐标
        }
        //重新初始化起始点为上次移动的终点 防止累加
        moveStartY = yDistance
        //修改rectF的top
        rectF.top += yMoveSpace

        //更新outSideRectF 点击是否选中的区域（矩形适用）
        newRectF.top += yMoveSpace

        //某些图形是否选中是根据裁切过后的具体图形路径mPath 所以也需要更新mPath（三角形 圆形 贝塞尔曲线等）
        //mPath.offset(xMoveSpace, yMoveSpace)
    }

    //移动操作中 改变图形下方长度的方法
    private fun changeBottomLength(yDistance: Float) {
        yMoveSpace = yDistance - moveStartY  //获取下方拉动距离
        //判断图形是如何拉动形成的（从上往下 从下往上）
        if (startY < endY) { //从上往下
            endY += yMoveSpace //修改终点的Y坐标
        } else { //从下往上
            startY += yMoveSpace //修改移动起始点的Y坐标
        }
        //重新初始化起始点为上次移动的终点 防止累加
        moveStartY = yDistance
        //修改rectF的top
        rectF.bottom += yMoveSpace

        //更新outSideRectF 点击是否选中的区域（矩形适用）
        newRectF.bottom += yMoveSpace

        //某些图形是否选中是根据裁切过后的具体图形路径mPath 所以也需要更新mPath（三角形 圆形 贝塞尔曲线等）
        //mPath.offset(xMoveSpace, yMoveSpace)
    }
}